package com.rock.app.controller.interceptor;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.eova.common.utils.xx;
import com.eova.config.EovaConst;
import com.eova.model.User;
import com.jfinal.aop.Interceptor;
import com.jfinal.aop.Invocation;
import com.jfinal.core.Controller;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.Ret;
import com.rock.app.base.OpenConsts;
import com.rock.app.base.OpenControllerBase;
import com.rock.sys.config.RockConst;
import com.rock.sys.model.TSApp;
import com.rock.sys.model.TSAppRelease;
import com.rock.sys.model.TUser;

import cn.hutool.core.util.StrUtil;

public class OpenInterceptor implements Interceptor {

	/**
	 * api 的有效时间，默认为 10 分钟
	 */
	private static final long TIMEOUT = 10 * 60 * 1000;

	public OpenInterceptor() {
	}

	@Override
	public void intercept(Invocation inv) {

		boolean apiEnable = xx.getConfigBool(OpenConsts.OPTION_API_ENABLE, true);
		String apiAppId = xx.getConfig(OpenConsts.OPTION_API_APPID);
		String apiSecret = xx.getConfig(OpenConsts.OPTION_API_SECRET);

		// API 功能未启用
		if (apiEnable == false) {
			inv.getController().renderJson(Ret.fail().set("message", "API功能已经关闭，请管理员在后台进行开启"));
			return;
		}

		if (StrUtil.isBlank(apiAppId)) {
			inv.getController().renderJson(Ret.fail().set("message", "后台配置的 APP ID 不能为空，请先进入后台的接口管理进行配置。"));
			return;
		}

		if (StrUtil.isBlank(apiSecret)) {
			inv.getController().renderJson(Ret.fail().set("message", "后台配置的 API 密钥不能为空，请先进入后台的接口管理进行配置。"));
			return;
		}

		OpenControllerBase controller = (OpenControllerBase) inv.getController();
		String queryString = controller.getRequest().getQueryString();
		if (StrUtil.isBlank(queryString)) {
			inv.getController().renderJson(Ret.fail().set("message", "请求参数错误。"));
			return;
		}
		Map<String, String> parasMap = paramToMap(queryString);

		String appId = parasMap.get("appId");
		if (StrUtil.isBlank(appId)) {
			inv.getController().renderJson(Ret.fail().set("message", "在Url中未获取到appId内容，请注意Url是否正确。"));
			return;
		}

		if (!appId.equals(apiAppId)) {
			inv.getController().renderJson(Ret.fail().set("message", "客户端配置的AppId和服务端配置的不一致。"));
			return;
		}

		String sign = parasMap.get("sign");
		if (StrUtil.isBlank(sign)) {
			controller.renderJson(Ret.fail("message", "签名数据不能为空，请提交 sign 数据。"));
			return;
		}

		String timeStr = parasMap.get("t");
		Long time = timeStr == null ? null : Long.valueOf(timeStr);
		if (time == null) {
			controller.renderJson(Ret.fail("message", "时间参数不能为空，请提交 t 参数数据。"));
			return;
		}

		// 时间验证，可以防止重放攻击
		if (Math.abs(System.currentTimeMillis() - time) > TIMEOUT) {
			controller.renderJson(Ret.fail("message", "请求超时，请重新请求。"));
			return;
		}

		String localSign = createLocalSign(controller);
		if (sign.equals(localSign) == false) {
			inv.getController().renderJson(Ret.fail().set("message", "数据签名错误。"));
			return;
		}

		// 设置用户信息
		Object userId = controller.getJwtPara(OpenConsts.JWT_USERID);
		if (userId != null) {
			// 业务层用户
			controller.setAttr(OpenConsts.ATTR_LOGINED_USER, TUser.dao.findById(userId));
			// 系统层用户
			User sysUser = User.dao.findById(userId);
			controller.setSessionAttr(EovaConst.USER, sysUser);
		}

		// APP应用标识 可能是rock的appcode，也可能是第三方的appid（适用于三方授权方式）
		String appCode = controller.getHeader(OpenConsts.APP_CODE_HEADER);
		
		if (!StrUtil.isBlank(appCode)) {

			// 查询APP及终端版本
			Map<String, Object> map = findByAppCodeOrChannelAppId(appCode);
			if (map.get("app") != null) {
				TSApp app = (TSApp) map.get("app");
				// 设置当前平台APP
				controller.setAttr(OpenConsts.ATTR_LOGINED_APP, app);
				// 设置当前平台APPID
				controller.setAttr(RockConst.ATTR_LOGINED_APP_ID, app.getId().toString());
			} else {
				inv.getController().renderJson(Ret.fail().set("message", "连接失败，无法识别APP标识"));
				return;
			}

			// 设置当前APP渠道
			if (map.get("appRelease") != null) {
				TSAppRelease appRelease = (TSAppRelease) map.get("appRelease");
				controller.setAttr(OpenConsts.ATTR_LOGINED_APP_RELEASE, appRelease);
			}

		} else {
			inv.getController().renderJson(Ret.fail().set("message", "连接失败，未传递APP标识"));
			return;
		}

		inv.invoke();
	}

	private String createLocalSign(Controller controller) {

		String apiSecret = xx.getConfig(OpenConsts.OPTION_API_SECRET);

		String queryString = controller.getRequest().getQueryString();
		Map<String, String[]> params = controller.getRequest().getParameterMap();

		String[] keys = params.keySet().toArray(new String[0]);
		Arrays.sort(keys);
		StringBuilder query = new StringBuilder();
		for (String key : keys) {
			if ("sign".equals(key)) {
				continue;
			}

			// 只对get参数里的进行签名
			if (queryString.indexOf(key + "=") == -1) {
				continue;
			}

			String value = params.get(key)[0];
			query.append(key).append(value);
		}
		query.append(apiSecret);
		return HashKit.md5(query.toString());
	}

	private static Map<String, String> paramToMap(String queryString) {
		String[] params = queryString.split("&");
		Map<String, String> resMap = new HashMap<>();
		for (int i = 0; i < params.length; i++) {
			String[] param = params[i].split("=");
			if (param.length >= 2) {
				String key = param[0];
				String value = param[1];
				for (int j = 2; j < param.length; j++) {
					value += "=" + param[j];
				}
				resMap.put(key, value);
			}
		}
		return resMap;
	}

	public Map<String, Object> findByAppCodeOrChannelAppId(String appCode) {
		// appCode，可能是rock的appcode，也可能是第三方的appid（适用于三方授权方式）
		// 优先根据三方的appid查询
		TSAppRelease appRelease = TSAppRelease.dao.findByChannelAppId(appCode);

		Map<String, Object> map = new HashMap<String, Object>();
		if (appRelease != null) {
			map.put("appRelease", appRelease);
			map.put("app", TSApp.dao.findById(appRelease.getAppId()));
			return map;
		} else {
			TSApp app = TSApp.dao.findByAppCode(appCode);
			if (app != null) {
				map.put("app", app);
				
				//根据app找到微信小程序密钥信息，如果不存在或找到多条，说明不正常，appRelease将置为null
				List<TSAppRelease> rs = TSAppRelease.dao.findByRockAppId(app.getId());
				if(rs.size() == 1) {
					map.put("appRelease", rs.get(0));
				}
			}
		}
		return map;
	}
}
